package com.swa99ylum.pxf.cell;

import java.util.Map;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;

import com.swa99ylum.pxf.Filler;
import com.swa99ylum.pxf.cell.adhesive.Adhesive;
import com.swa99ylum.pxf.cell.indexer.CellIndexer;
import com.swa99ylum.pxf.cell.indexer.FixedCellIndexer;
import com.swa99ylum.pxf.cell.injector.AdaptableCellInjector;
import com.swa99ylum.pxf.cell.injector.CellInjector;
import com.swa99ylum.pxf.cell.styler.CellStyler;
import com.swa99ylum.pxf.cell.styler.SimpleStyler;

public class CellFiller extends Filler {
	
	private int beginIndex;
	private CellIndexer cellIndexer;
	
	private XSSFCell[] 		cells; 		//RowFiller.fill() 的时候会 赋值
	
	private Object[] 		properties;
	private Object[] 		cellValues; //RowFiller.fill() 的时候会 赋值
	
	
	/**
	 * cell 和 injector、styler 之间是 "多对一" 的 关系，
	 * 即 "多个cell" 可以使用 "一个injector、一个styler" 进行填充
	 */
	/** 注射器	*/
	private CellInjector injector;
	/** 样式器	*/
	private CellStyler styler;
//	private CellFormulator formulator; 	//TODO: 将来可能会被 抽象出 的 对象
//	private CellTyper typer; 			//TODO: 将来可能会被 抽象出 的 对象
	
	
	/** 粘合剂：用于 合并单元格	*/
	private Adhesive adhesive;
	
	/** "本组 CellFiller 的 第一列" 是否允许和 "左一列" 发生 黏连	*/
	private boolean adherePreviousColumn;
	
	/** 是否允许 "纵向黏连"。该属性 呼应于 RowFiller 的 adherePreviousRow 属性 */
	private Boolean allowVetAdhesive;
	
	
	/** 默认的 提取器：AdaptableCellInjector  */
	//20180717：不能这样写，不能把 AdaptableCellInjector 定义成 类共享变量（static），这会引发 :
	//Are you trying to assign a style from one workbook to the cell of a different workbook?
//	private final static CellInjector	DEFAULT_INJECTOR  = new AdaptableCellInjector(); 
//	private static CellInjector getDefaultInjector() {
//		return new AdaptableCellInjector();
//	}
	
	/**
	 * 默认："本组 CellFiller 的 第一列" 默认不允许 和 "左一列" 发生 黏连，即 隔断 "本组 CellFiller" 和 左方的 黏连
	 */
	private final static boolean		DEFAULT_ADHERE_PREVIOUS_COLUMN = false;

	
	
	/*--------------------------------------------
    |      				核心方法			         |
    ============================================*/

	
	/** styleMap 的 注入链	*/
	@Override
	public void spreadStyleMap(Map<String, XSSFCellStyle> styleMap) {
		if(styler != null) styler.setStyleMap(styleMap);
	}
	
	
	/**
	 * 核心方法：填充 row 上的 cell
	 */
	public void fill() {
		
		
		for (int i = 0; i < cells.length; i++) {
			
			XSSFCell cell = cells[i];
			Object cellValue = cellValues[i];
			
			
			/** step1、设置 单元格的 "值"、"样式" */
			
			if(styler!=null)	injector.setStyler(styler);
			else				injector.setStyler(null);
//			if(formulator!=null)injector.setFormulator(formulator);
//			else				injector.setFormulator(null);
//			if(typer!=null)		injector.setTyper(typer);
//			else				injector.setTyper(null);
			
			injector.inject(cell, cellValue); //设置 单元格的值
			
			
			/*
			 * 补充1、
			 * 合并单元格 之后，肉眼看到的 mr 的 "值"、"样式"、"公式"，均以 "左上角cell" 为准
			 * 
			 * 补充2、
			 * adhesive.equals(cell1, cell2) 比较的是 XSSFCell，并不是 cellValue
			 * 即 判等时，会再次从 XSSFCell 中读取 刚刚 注射器 inject 进去的 值，这个值 是经过 injector 加工过的，是 实际落地 到 xlsx 的 单元格 上的 值
			 * 
			 * 其实，也可以 拿 样式器 设置的 "样式" 来进行 判等，开发者可以 自定义 "判等策略" 
			 * 
			 */
			
			
			/** step2、尝试 合并单元格 */
			/*
			 * 如果 设置了 粘合剂，则：先 尝试"横向黏连"、再 尝试"纵向黏连"
			 * 如果 当前 cell，和 左方 / 上方 的  cell 之间 满足了 "黏连条件"(函数式，可由 开发者 自定义)，则 能够触发 "合并单元格"
			 */
			if(adhesive != null) {
				
				/* 尝试"横向黏连" */
				if(adhesive.hasHizAdhesive()) { //具有 "横向粘合能力"
					
					if(i==0 && !adherePreviousColumn) {
						/* 
						 * 如果：
						 * 1、当前列 为 本组第一列
						 * 2、"本组 CellFiller 的 第一列" 不黏连 "左一列"
						 * 
						 * 那么：
						 * 不做任何 横向黏连 操作，即：则 该列上的  所有 cell 都不会和 左一列 发生黏连
						 */
						
					}else {
						adhesive.adhereHorizontally(cell);
					}
				}
				
				/* 尝试 "纵向黏连" */
				if(allowVetAdhesive && adhesive.hasVetAdhesive()) { //具有 "纵向粘合能力"，并且 允许使用 "纵向粘合能力"
					
					adhesive.adhereVertically(cell);
					
				}
					
			}
				
		}
		
	}
	
	
	
	/*--------------------------------------------
    |      			49 个  构造器			         |
    ============================================*/
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, CellStyler styler,
			Adhesive adhesive, boolean adherePreviousColumn) {
		super();
		
		this.beginIndex = -1;
		
		/* 2 个 必填项 */
		this.cellIndexer = cellIndexer;
		this.properties = properties;
		
		/* 可选项 1：injector */
		this.injector = injector;
		
		/* 可选项 2：styler */
		this.styler = styler;
//		this.formulator = formulator;
//		this.typer = typer;

		/* 可选项 3：adhesive */
		this.adhesive = adhesive;
		
		/* 可选项 3-4：adhesive + aPC */
		this.adherePreviousColumn = adherePreviousColumn;
		

	}
	
	/** 提供 0 个 可选项 => 共 3  个 */
	/* 不提供任何 可选项 => 共 3  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties) {
		this(cellIndexer, properties, new AdaptableCellInjector() /** getDefaultInjector() DEFAULT_INJECTOR */, null, null, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties) {
		/**
		 * 即使 提供了 beginIndex，也走 Indexer 算法：默认 使用 FixedRangeCellIndexer(beginIndex)
		 * 原因：为了在 fill() 的 时候 统一代码
		 */
		//this.beginIndex = beginIndex;
		this(new FixedCellIndexer(beginIndex), properties);
	}
	public CellFiller(Object[] properties) {
		this(null, properties);
	}
	
	/** 提供 1 个 可选项 => 共 12  个 */
	/* 提供 可选项 1 => 共 3  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector) {
		this(cellIndexer, properties, injector, null, null, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector) {
		this(new FixedCellIndexer(beginIndex), properties, injector);
	}
	public CellFiller(Object[] properties, CellInjector injector) {
		this(null, properties, injector);
	}
	
	/* 提供 可选项 2 => 共 6  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellStyler styler) {
		this(cellIndexer, properties, new AdaptableCellInjector() /** getDefaultInjector()  DEFAULT_INJECTOR */, styler, null, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, CellStyler styler) {
		this(new FixedCellIndexer(beginIndex), properties, styler);
	}
	public CellFiller(Object[] properties, CellStyler styler) {
		this(null, properties, styler);
	}
	public CellFiller(CellIndexer cellIndexer, Object[] properties, String styleAddress) {
		this(cellIndexer, properties, new SimpleStyler(styleAddress));
	}
	public CellFiller(int beginIndex, Object[] properties, String styleAddress) {
		this(new FixedCellIndexer(beginIndex), properties, new SimpleStyler(styleAddress));
	}
	public CellFiller(Object[] properties, String styleAddress) {
		this(null, properties, new SimpleStyler(styleAddress));
	}
	
	/* 提供 可选项 3 => 共 3  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, Adhesive adhesive) {
		this(cellIndexer, properties, new AdaptableCellInjector() /** getDefaultInjector()  DEFAULT_INJECTOR */, null, adhesive, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, Adhesive adhesive) {
		this(new FixedCellIndexer(beginIndex), properties, adhesive);
	}
	public CellFiller(Object[] properties, Adhesive adhesive) {
		this(null, properties, adhesive);
	}
	
	
	/** 提供 2 个 可选项 => 共 18  个 */
	/* 提供 可选项 1、2 => 共 6  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, CellStyler styler) {
		this(cellIndexer, properties, injector, styler, null, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector, CellStyler styler) {
		this(new FixedCellIndexer(beginIndex), properties, injector, styler);
	}
	public CellFiller(Object[] properties, CellInjector injector, CellStyler styler) {
		this(null, properties, injector, styler);
	}
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, String styleAddress) {
		this(cellIndexer, properties, injector, new SimpleStyler(styleAddress));
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector, String styleAddress) {
		this(new FixedCellIndexer(beginIndex), properties, injector, new SimpleStyler(styleAddress));
	}
	public CellFiller(Object[] properties, CellInjector injector, String styleAddress) {
		this(null, properties, injector, new SimpleStyler(styleAddress));
	}
	
	/* 提供 可选项 1、3 => 共 3  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, Adhesive adhesive) {
		this(cellIndexer, properties, injector, null, adhesive, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector, Adhesive adhesive) {
		this(new FixedCellIndexer(beginIndex), properties, injector, adhesive);
	}
	public CellFiller(Object[] properties, CellInjector injector, Adhesive adhesive) {
		this(null, properties, injector, adhesive);
	}
	
	/* 提供 可选项 2、3 => 共 6  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellStyler styler, Adhesive adhesive) {
		this(cellIndexer, properties, new AdaptableCellInjector() /** getDefaultInjector()  DEFAULT_INJECTOR */, styler, adhesive, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, CellStyler styler, Adhesive adhesive) {
		this(new FixedCellIndexer(beginIndex), properties, styler, adhesive);
	}
	public CellFiller(Object[] properties, CellStyler styler, Adhesive adhesive) {
		this(null, properties, styler, adhesive);
	}
	public CellFiller(CellIndexer cellIndexer, Object[] properties, String styleAddress, Adhesive adhesive) {
		this(cellIndexer, properties, new SimpleStyler(styleAddress), adhesive);
	}
	public CellFiller(int beginIndex, Object[] properties, String styleAddress, Adhesive adhesive) {
		this(new FixedCellIndexer(beginIndex), properties, new SimpleStyler(styleAddress), adhesive);
	}
	public CellFiller(Object[] properties, String styleAddress, Adhesive adhesive) {
		this(null, properties, new SimpleStyler(styleAddress), adhesive);
	}

	/* 提供 可选项 3-4 => 共 3  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, Adhesive adhesive, boolean adherePreviousColumn) {
		this(cellIndexer, properties, new AdaptableCellInjector() /** getDefaultInjector()  DEFAULT_INJECTOR */, null, adhesive, adherePreviousColumn);
	}
	public CellFiller(int beginIndex, Object[] properties, Adhesive adhesive, boolean adherePreviousColumn) {
		this(new FixedCellIndexer(beginIndex), properties, adhesive, adherePreviousColumn);
	}
	public CellFiller(Object[] properties, Adhesive adhesive, boolean adherePreviousColumn) {
		this(null, properties, adhesive, adherePreviousColumn);
	}
	
	
	/** 提供 3 个 可选项 => 共 15  个 */
	/* 提供 可选项 1、2、3 => 共 6  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, CellStyler styler, Adhesive adhesive) {
		this(cellIndexer, properties, injector, styler, adhesive, DEFAULT_ADHERE_PREVIOUS_COLUMN);
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector, CellStyler styler, Adhesive adhesive) {
		this(new FixedCellIndexer(beginIndex), properties, injector, styler, adhesive);
	}
	public CellFiller(Object[] properties, CellInjector injector, CellStyler styler, Adhesive adhesive) {
		this(null, properties, injector, styler, adhesive);
	}
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, String styleAddress, Adhesive adhesive) {
		this(cellIndexer, properties, injector, new SimpleStyler(styleAddress), adhesive);
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector, String styleAddress, Adhesive adhesive) {
		this(new FixedCellIndexer(beginIndex), properties, injector, new SimpleStyler(styleAddress), adhesive);
	}
	public CellFiller(Object[] properties, CellInjector injector, String styleAddress, Adhesive adhesive) {
		this(null, properties, injector, new SimpleStyler(styleAddress), adhesive);
	}
	
	/* 提供 可选项 1、3-4 => 共 3  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellInjector injector, Adhesive adhesive, boolean adherePreviousColumn) {
		this(cellIndexer, properties, injector, null, adhesive, adherePreviousColumn);
	}
	public CellFiller(int beginIndex, Object[] properties, CellInjector injector, Adhesive adhesive, boolean adherePreviousColumn) {
		this(new FixedCellIndexer(beginIndex), properties, injector, adhesive, adherePreviousColumn);
	}
	public CellFiller(Object[] properties, CellInjector injector, Adhesive adhesive, boolean adherePreviousColumn) {
		this(null, properties, injector, adhesive, adherePreviousColumn);
	}
	
	/* 提供 可选项 2、3-4 => 共 6  个 */
	public CellFiller(CellIndexer cellIndexer, Object[] properties, CellStyler styler, Adhesive adhesive, boolean adherePreviousColumn) {
		this(cellIndexer, properties, new AdaptableCellInjector() /** getDefaultInjector()  DEFAULT_INJECTOR */, styler, adhesive, adherePreviousColumn);
	}
	public CellFiller(int beginIndex, Object[] properties, CellStyler styler, Adhesive adhesive, boolean adherePreviousColumn) {
		this(new FixedCellIndexer(beginIndex), properties, styler, adhesive, adherePreviousColumn);
	}
	public CellFiller(Object[] properties, CellStyler styler, Adhesive adhesive, boolean adherePreviousColumn) {
		this(null, properties, styler, adhesive, adherePreviousColumn);
	}
	public CellFiller(CellIndexer cellIndexer, Object[] properties, String styleAddress, Adhesive adhesive, boolean adherePreviousColumn) {
		this(cellIndexer, properties, new SimpleStyler(styleAddress), adhesive, adherePreviousColumn);
	}
	public CellFiller(int beginIndex, Object[] properties, String styleAddress, Adhesive adhesive, boolean adherePreviousColumn) {
		this(new FixedCellIndexer(beginIndex), properties, new SimpleStyler(styleAddress), adhesive, adherePreviousColumn);
	}
	public CellFiller(Object[] properties, String styleAddress, Adhesive adhesive, boolean adherePreviousColumn) {
		this(null, properties, new SimpleStyler(styleAddress), adhesive, adherePreviousColumn);
	}
	
	
	
	/*--------------------------------------------
    |      			getter、setter		         |
    ============================================*/
	public int getBeginIndex() {
		return beginIndex;
	}

	public void setBeginIndex(int beginIndex) {
		this.beginIndex = beginIndex;
	}

	public CellIndexer getCellIndexer() {
		return cellIndexer;
	}

	public void setCellIndexer(CellIndexer cellIndexer) {
		this.cellIndexer = cellIndexer;
	}

	public XSSFCell[] getCells() {
		return cells;
	}

	public void setCells(XSSFCell[] cells) {
		this.cells = cells;
	}

	public Object[] getProperties() {
		return properties;
	}

	public void setProperties(Object[] properties) {
		this.properties = properties;
	}

	public Object[] getCellValues() {
		return cellValues;
	}

	public void setCellValues(Object[] cellValues) {
		this.cellValues = cellValues;
	}

	public CellInjector getInjector() {
		return injector;
	}

	public void setInjector(CellInjector injector) {
		this.injector = injector;
	}

	public CellStyler getStyler() {
		return styler;
	}

	public void setStyler(CellStyler styler) {
		this.styler = styler;
	}

	public Adhesive getAdhesive() {
		return adhesive;
	}

	public void setAdhesive(Adhesive adhesive) {
		this.adhesive = adhesive;
	}

	public boolean isAdherePreviousColumn() {
		return adherePreviousColumn;
	}

	public void setAdherePreviousColumn(boolean adherePreviousColumn) {
		this.adherePreviousColumn = adherePreviousColumn;
	}

	public Boolean isAllowVetAdhesive() {
		return allowVetAdhesive;
	}

//	public void setAllowVetAdhesive(boolean allowVetAdhesive) {
//		this.allowVetAdhesive = allowVetAdhesive;
//	}
	
	public CellFiller setAllowVetAdhesive(boolean allowVetAdhesive) {
		//20180714，如果 allowVetAdhesive 原本就有值，则 不进行 赋值操作
		this.allowVetAdhesive = allowVetAdhesive;
		return this;
	}
	
	
	public static void main(String[] args) {
		CellFiller cf = new CellFiller(null);
		System.out.println(cf.isAllowVetAdhesive());
	}
	
}
